﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Models;
using System.Windows.Controls.Primitives;

namespace UIControls.PropertyGrid
{

    public class PropertyGrid : Control
    {
        static PropertyGrid()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(PropertyGrid), new FrameworkPropertyMetadata(typeof(PropertyGrid)));
        }

        public List<Type> ShowTypes { get; set; }

        public PropertyGrid()
        {
            this.DataContext = this;
            this.ShowTypes = new List<Type>();
            this.ShowTypes.Add(typeof(Models.Property));
            //this.ShowTypes.Add(typeof(TimeSpan));

            this.KeyDown += new KeyEventHandler(PropertyGrid_KeyDown);
        }

        void PropertyGrid_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                if (e.OriginalSource is TextBox)
                {
                    TextBox t = (TextBox)e.OriginalSource;
                    if (t.DataContext is Property)
                    {
                        ((Property)t.DataContext).Value = t.Text;
                    }
                    e.KeyboardDevice.ClearFocus();
                }
            }
        }

        #region Name Width Property and Dragging

        public static DependencyProperty NameWidthProperty =
            DependencyProperty.Register("NameWidth", typeof(double), typeof(PropertyGrid),
                                        new PropertyMetadata(50.0));

        public double NameWidth
        {
            get { return (double)GetValue(NameWidthProperty); }
            set { SetValue(NameWidthProperty, value); }
        }

        private void PART_Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            NameWidth = Math.Max(0, NameWidth + e.HorizontalChange);
        }

        #endregion

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            object myThumb = Template.FindName("PART_Thumb", this);
            if (myThumb != null && myThumb is Thumb)
                ((Thumb)myThumb).DragDelta += new DragDeltaEventHandler(PART_Thumb_DragDelta);

           // Refresh();
        }

        #region Instance Property

        /// <value>Identifies the Instance dependency property</value>
        public static readonly DependencyProperty InstanceProperty =
            DependencyProperty.Register("Instance", typeof(object), typeof(PropertyGrid),
            new FrameworkPropertyMetadata(null, OnInstanceChanged, CoerceInstance));

        /// <value>description for Instance property</value>
        public object Instance
        {
            get { return (object)GetValue(InstanceProperty); }
            set { SetValue(InstanceProperty, value); }
        }

        /// <summary>
        /// Invoked on Instance change.
        /// </summary>
        /// <param name="d">The object that was changed</param>
        /// <param name="e">Dependency property changed event arguments</param>
        static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PropertyGrid propertyGrid = d as PropertyGrid;

            object sender = e.NewValue;
            //if (sender is ListBox)
            {
                //object o = ((ListBox)sender).SelectedItem;
                object o = e.NewValue;
                ObservableCollection<Property> pc = new ObservableCollection<Property>();
                if (o != null)
                {
                    Type t = o.GetType();
                    System.Reflection.PropertyInfo[] properties = t.GetProperties();
                    foreach (System.Reflection.PropertyInfo property in properties)
                    {
                        if (propertyGrid.ShowTypes.Contains(property.PropertyType))
                        {
                            try
                            {
                                object v = property.GetValue(o, null);
                                if (v is Property)
                                {
                                    pc.Add(v as Property);
                                }
                                else
                                {
                                    pc.Add(new Property()
                                    {
                                        Text = property.Name,
                                        Value = property.GetValue(o, null).ToString(),
                                        Type = property.PropertyType,
                                        Source = o
                                    });
                                }
                            }
                            catch (Exception)
                            {
                                
                            }
                        }
                    }
                }
                //this.datagridProperty.ItemsSource = pc;
                propertyGrid.Properties = pc;

            }
        }
            

        static object CoerceInstance(DependencyObject d, object value)
        {
            PropertyGrid propertyGrid = d as PropertyGrid;
            if (value == null)
            {
                return propertyGrid.NullInstance;
            }
            return value;
        }
        #endregion

        #region NullInstance Property

        /// <value>Identifies the NullInstance dependency property</value>
        public static readonly DependencyProperty NullInstanceProperty =
            DependencyProperty.Register("NullInstance", typeof(object), typeof(PropertyGrid),
            new FrameworkPropertyMetadata(null, OnNullInstanceChanged));

        /// <value>description for NullInstance property</value>
        public object NullInstance
        {
            get { return (object)GetValue(NullInstanceProperty); }
            set { SetValue(NullInstanceProperty, value); }
        }

        /// <summary>
        /// Invoked on NullInstance change.
        /// </summary>
        /// <param name="d">The object that was changed</param>
        /// <param name="e">Dependency property changed event arguments</param>
        static void OnNullInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion


        #region Properties Property

        /// <value>Identifies the Properties dependency property</value>
        public static readonly DependencyProperty PropertiesProperty =
            DependencyProperty.Register("Properties", typeof(ObservableCollection<Property>), typeof(PropertyGrid),
            new FrameworkPropertyMetadata(new ObservableCollection<Property>(), OnPropertiesChanged));

        /// <value>description for Properties property</value>
        public ObservableCollection<Property> Properties
        {
            get { return (ObservableCollection<Property>)GetValue(PropertiesProperty); }
            set { SetValue(PropertiesProperty, value); }
        }

        static void OnPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //PropertyGrid propertyGrid = d as PropertyGrid;
            //ObservableCollection<Item> properties = e.OldValue as ObservableCollection<Item>;
            //foreach (Item item in properties)
            //{
            //    item.Dispose();
            //}
        }

        #endregion
    }
}
